deltas: Flesh out the open/write/close opcodes
authorColin Walters <walters@verbum.org>
Fri, 30 Jan 2015 03:32:44 +0000 (22:32 -0500)
committerColin Walters <walters@verbum.org>
Mon, 16 Feb 2015 15:10:35 +0000 (10:10 -0500)
Refactor open-splice-and-close to call open/close.  We can't just call
write as that would require duplicating the object size parameter.

src/libostree/ostree-repo-static-delta-processing.c

index cd77adb4c93e64cb0d6908f81875a52684bd2ef3..10372a02aae5a0020582c3eb103978c818aa9c89 100644 (file)
@@ -54,6 +54,16 @@ typedef struct {
   GError        **async_error;
 
   OstreeObjectType output_objtype;
+  OstreeRepoTrustedContentBareCommit barecommitstate;
+  guint64          content_size;
+  GOutputStream   *content_out;
+  char             checksum[65];
+  gboolean        have_obj;
+  guint32         uid;
+  guint32         gid;
+  guint32         mode;
+  GVariant       *xattrs;
+  
   const guint8   *output_target;
   const guint8   *input_target_csum;
 
@@ -113,7 +123,6 @@ open_output_target (StaticDeltaExecutionState   *state,
 {
   gboolean ret = FALSE;
   guint8 *objcsum;
-  char checksum[65];
 
   g_assert (state->checksums != NULL);
   g_assert (state->output_target == NULL);
@@ -127,7 +136,7 @@ open_output_target (StaticDeltaExecutionState   *state,
   state->output_objtype = (OstreeObjectType) *objcsum;
   state->output_target = objcsum + 1;
 
-  ostree_checksum_inplace_from_bytes (state->output_target, checksum);
+  ostree_checksum_inplace_from_bytes (state->output_target, state->checksum);
 
   ret = TRUE;
  out:
@@ -438,6 +447,38 @@ validate_ofs (StaticDeltaExecutionState  *state,
   return TRUE;
 }
 
+static gboolean
+do_content_open_generic (OstreeRepo                 *repo,
+                         StaticDeltaExecutionState  *state,
+                         GCancellable               *cancellable,  
+                         GError                    **error)
+{
+  gboolean ret = FALSE;
+  gs_unref_variant GVariant *modev;
+  guint64 mode_offset;
+  guint64 xattr_offset;
+  guint32 uid, gid, mode;
+
+  if (!read_varuint64 (state, &mode_offset, error))
+    goto out;
+  if (!read_varuint64 (state, &xattr_offset, error))
+    goto out;
+
+  state->barecommitstate.fd = -1;
+
+  modev = g_variant_get_child_value (state->mode_dict, mode_offset);
+  g_variant_get (modev, "(uuu)", &uid, &gid, &mode);
+  state->uid = GUINT32_FROM_BE (uid);
+  state->gid = GUINT32_FROM_BE (gid);
+  state->mode = GUINT32_FROM_BE (mode);
+
+  state->xattrs = g_variant_get_child_value (state->xattr_dict, xattr_offset);
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
 static gboolean
 dispatch_open_splice_and_close (OstreeRepo                 *repo,
                                 StaticDeltaExecutionState  *state,
@@ -445,13 +486,10 @@ dispatch_open_splice_and_close (OstreeRepo                 *repo,
                                 GError                    **error)
 {
   gboolean ret = FALSE;
-  char checksum[65];
 
   if (!open_output_target (state, cancellable, error))
     goto out;
-
-  ostree_checksum_inplace_from_bytes (state->output_target, checksum);
-
+  
   if (OSTREE_OBJECT_TYPE_IS_META (state->output_objtype))
     {
       gs_unref_variant GVariant *metadata = NULL;
@@ -469,7 +507,7 @@ dispatch_open_splice_and_close (OstreeRepo                 *repo,
                                           state->payload_data + offset, length, TRUE, NULL, NULL);
       
       if (!ostree_repo_write_metadata_trusted (state->repo, state->output_objtype,
-                                               checksum,
+                                               state->checksum,
                                                metadata,
                                                cancellable,
                                                error))
@@ -477,81 +515,54 @@ dispatch_open_splice_and_close (OstreeRepo                 *repo,
     }
   else
     {
-      guint64 mode_offset;
-      guint64 xattr_offset;
-      guint64 content_size;
       guint64 content_offset;
       guint64 objlen;
+      guint64 content_size;
+      gsize bytes_written;
       gs_unref_object GInputStream *object_input = NULL;
       gs_unref_object GInputStream *memin = NULL;
-      gs_unref_variant GVariant *xattrs_buf = NULL;
-      GVariant *modev;
-      GVariant *xattrs;
-      guint32 uid, gid, mode;
-
-      if (!read_varuint64 (state, &mode_offset, error))
-        goto out;
-      if (!read_varuint64 (state, &xattr_offset, error))
+      
+      if (!do_content_open_generic (repo, state, cancellable, error))
         goto out;
+
       if (!read_varuint64 (state, &content_size, error))
         goto out;
       if (!read_varuint64 (state, &content_offset, error))
         goto out;
-
       if (!validate_ofs (state, content_offset, content_size, error))
         goto out;
-
-      modev = g_variant_get_child_value (state->mode_dict, mode_offset);
-      g_variant_get (modev, "(uuu)", &uid, &gid, &mode);
-      uid = GUINT32_FROM_BE (uid);
-      gid = GUINT32_FROM_BE (gid);
-      mode = GUINT32_FROM_BE (mode);
-
-      xattrs = g_variant_get_child_value (state->xattr_dict, xattr_offset);
-
+      
       /* Fast path for regular files to bare repositories */
-      if (S_ISREG (mode) && 
+      if (S_ISREG (state->mode) && 
           (repo->mode == OSTREE_REPO_MODE_BARE ||
            repo->mode == OSTREE_REPO_MODE_BARE_USER))
         {
-          OstreeRepoTrustedContentBareCommit barecommitstate = { -1 };
-          gs_unref_object GOutputStream *outstream = NULL;
-          gsize bytes_written;
-          gboolean have_obj;
-
-          if (!_ostree_repo_open_trusted_content_bare (repo, checksum,
-                                                       content_size,
-                                                       &barecommitstate,
-                                                       &outstream,
-                                                       &have_obj,
+          if (!_ostree_repo_open_trusted_content_bare (repo, state->checksum,
+                                                       state->content_size,
+                                                       &state->barecommitstate,
+                                                       &state->content_out,
+                                                       &state->have_obj,
                                                        cancellable, error))
             goto out;
-          
-          if (!have_obj)
+
+          if (!state->have_obj)
             {
-              if (!g_output_stream_write_all (outstream, state->payload_data + content_offset,
+              if (!g_output_stream_write_all (state->content_out,
+                                              state->payload_data + content_offset,
                                               content_size,
                                               &bytes_written,
                                               cancellable, error))
                 goto out;
-
-              if (!g_output_stream_flush (outstream, cancellable, error))
-                goto out;
             }
-
-          if (!_ostree_repo_commit_trusted_content_bare (repo, checksum, &barecommitstate,
-                                                         uid, gid, mode, xattrs,
-                                                         cancellable, error))
-            goto out;
         }
       else
         {
           /* Slower path, for symlinks and unpacking deltas into archive-z2 */
           gs_unref_object GFileInfo *finfo = NULL;
       
-          finfo = _ostree_header_gfile_info_new (mode, uid, gid);
+          finfo = _ostree_header_gfile_info_new (state->mode, state->uid, state->gid);
 
-          if (S_ISLNK (mode))
+          if (S_ISLNK (state->mode))
             {
               gs_free char *nulterminated_target =
                 g_strndup ((char*)state->payload_data + content_offset, content_size);
@@ -559,18 +570,18 @@ dispatch_open_splice_and_close (OstreeRepo                 *repo,
             }
           else
             {
-              g_assert (S_ISREG (mode));
+              g_assert (S_ISREG (state->mode));
               g_file_info_set_size (finfo, content_size);
               memin = g_memory_input_stream_new_from_data (state->payload_data + content_offset, content_size, NULL);
             }
 
-          if (!ostree_raw_file_to_content_stream (memin, finfo, xattrs,
+          if (!ostree_raw_file_to_content_stream (memin, finfo, state->xattrs,
                                                   &object_input, &objlen,
                                                   cancellable, error))
             goto out;
           
           if (!ostree_repo_write_content_trusted (state->repo,
-                                                  checksum,
+                                                  state->checksum,
                                                   object_input,
                                                   objlen,
                                                   cancellable,
@@ -579,8 +590,8 @@ dispatch_open_splice_and_close (OstreeRepo                 *repo,
         }
     }
 
-  state->checksum_index++;
-  state->output_target = NULL;
+  if (!dispatch_close (repo, state, cancellable, error))
+    goto out;
 
   ret = TRUE;
  out:
@@ -597,9 +608,25 @@ dispatch_open (OstreeRepo                 *repo,
 {
   gboolean ret = FALSE;
 
+  g_assert (state->output_target == NULL);
+  /* FIXME - lift this restriction */
+  g_assert (repo->mode == OSTREE_REPO_MODE_BARE ||
+            repo->mode == OSTREE_REPO_MODE_BARE_USER);
+  
   if (!open_output_target (state, cancellable, error))
     goto out;
 
+  if (!do_content_open_generic (repo, state, cancellable, error))
+    goto out;
+
+  if (!_ostree_repo_open_trusted_content_bare (repo, state->checksum,
+                                               state->content_size,
+                                               &state->barecommitstate,
+                                               &state->content_out,
+                                               &state->have_obj,
+                                               cancellable, error))
+    goto out;
+
   ret = TRUE;
  out:
   if (!ret)
@@ -614,11 +641,29 @@ dispatch_write (OstreeRepo                 *repo,
                GError                    **error)
 {
   gboolean ret = FALSE;
+  guint64 content_size;
+  guint64 content_offset;
+  gsize bytes_written;
+      
+  if (!read_varuint64 (state, &content_size, error))
+    goto out;
+  if (!read_varuint64 (state, &content_offset, error))
+    goto out;
+  if (!validate_ofs (state, content_offset, content_size, error))
+    goto out;
 
-  g_assert_not_reached ();
+  if (!state->have_obj)
+    {
+      if (!g_output_stream_write_all (state->content_out,
+                                      state->payload_data + content_offset,
+                                      content_size,
+                                      &bytes_written,
+                                      cancellable, error))
+        goto out;
+    }
   
   ret = TRUE;
-  /* out: */
+ out:
   if (!ret)
     g_prefix_error (error, "opcode open-splice-and-close: ");
   return ret;
@@ -648,11 +693,27 @@ dispatch_close (OstreeRepo                 *repo,
                 GError                    **error)
 {
   gboolean ret = FALSE;
+  
+  if (state->content_out)
+    {
+      if (!g_output_stream_flush (state->content_out, cancellable, error))
+        goto out;
 
-  g_assert_not_reached ();
+      if (!_ostree_repo_commit_trusted_content_bare (repo, state->checksum, &state->barecommitstate,
+                                                     state->uid, state->gid, state->mode,
+                                                     state->xattrs,
+                                                     cancellable, error))
+        goto out;
+    }
+      
+  g_clear_pointer (&state->xattrs, g_variant_unref);
+  g_clear_object (&state->content_out);
   
+  state->checksum_index++;
+  state->output_target = NULL;
+
   ret = TRUE;
-  /* out: */
+ out:
   if (!ret)
     g_prefix_error (error, "opcode open-splice-and-close: ");
   return ret;